#include "cc_queue.h"
#include "cc_log.h"
#include "cc_mempool.h"

void cc_queue_init(cc_que_t que, uint8_t* que_storage_arr, uint32_t num,
                   uint32_t size)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return;
  }
  que->capacity = num;
  que->len = 0;
  que->que = xQueueCreateStatic(num, size, que_storage_arr, &que->entity);
  return;
}

cc_que_t cc_queue_create(uint32_t num, uint32_t size)
{
  cc_que_t que = (cc_que_t)cc_malloc(sizeof(cc_que));
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return CC_NULL;
  }
  uint8_t* que_storage_arr =
      (uint8_t*)cc_malloc(GET_QUEUE_STORAGE_SIZE(num, size));
  if (que_storage_arr == CC_NULL)
  {
    cc_log_e("que_storage_arr is null\r\n");
    return CC_NULL;
  }
  cc_queue_init(que, que_storage_arr, num, size);
  return que;
}

void cc_queue_deinit(cc_que_t que)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return;
  }
  vQueueDelete(que->que);
  que->capacity = 0;
  que->len = 0;
  return;
}

void cc_queue_destory(cc_que_t que)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return;
  }
  cc_queue_deinit(que);
  cc_free(que);
  return;
}

int cc_queue_send_time(cc_que_t que, const void* msg, TickType_t ms)
{

  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return CC_ENOMEM;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xQueueSendFromISR(que->que, msg, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xQueueSend(que->que, msg, ms);
}

int cc_queue_send(cc_que_t que, const void* msg)
{

  return cc_queue_send_time(que, msg, CC_TIME_WAIT_FOREVER);
}

int cc_queue_send_try(cc_que_t que, const void* msg)
{

  return cc_queue_send_time(que, msg, 0);
}

int cc_queue_send_urgent_time(cc_que_t que, const void* msg, TickType_t ms)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return cc_false;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xQueueSendToFrontFromISR(que->que, msg, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xQueueSendToFront(que->que, msg, ms);
}

int cc_queue_send_urgent_try(cc_que_t que, const void* msg)
{

  return cc_queue_send_urgent_time(que, msg, 0);
}

int cc_queue_send_urgent(cc_que_t que, const void* msg)
{
  return cc_queue_send_urgent_time(que, msg, CC_TIME_WAIT_FOREVER);
}

int cc_queue_send_overwrite(cc_que_t que, const void* msg)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return cc_false;
  }
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xQueueOverwriteFromISR(que->que, msg, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xQueueOverwrite(que->que, msg);
}

int cc_queue_recv_time(cc_que_t que, void* buf, TickType_t ms)
{
  if (que == CC_NULL)
  {
    cc_log_e("que is null\r\n");
    return cc_false;
  }

  que->len--;
  if (cc_is_in_isr())
  {
    BaseType_t xHigherPriorityTaskWoken;
    int status = xQueueReceiveFromISR(que->que, buf, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    return status;
  }
  return xQueueReceive(que->que, buf, ms);
}

int cc_queue_recv(cc_que_t que, void* buf)
{

  return cc_queue_recv_time(que, buf, CC_TIME_WAIT_FOREVER);
}

int cc_queue_recv_try(cc_que_t que, void* buf)
{
  return cc_queue_recv_time(que, buf, 0);
}

/**
 * @brief get a node to enque,if you want the mem of the node is alloc by
 * mempool ,hdl should not be cc_NULL ,and if you want the node's data_domain
 * not be NULL ,you also need to set the second param, otherwise the first and
 * second param can be cc_NULL like the QueueSimple1.c
 * @param hdl mempool(if set cc_NULL the node mem will be cc_malloc)
 * @param mem node data_doain(if set cc_NULL the node will no use data_domain)
 * @param sz the size of node
 * @param timeout the wait alloc time if you use mempool to alloc mem
 * @return node
 */
struct cc_mnode* cc_mnode_get(cc_mempool_t hdl, void* mem, size_t sz,
                              uint32_t timeout, cc_mn_callback cb)
{
  struct cc_mnode* node;
  if (!hdl)
  {
    node = (struct cc_mnode*)cc_malloc(sz);
  }
  else
    node = (struct cc_mnode*)cc_mempool_alloc_time(hdl, timeout);
  if (node)
  {
    memset(node, 0, sizeof(struct cc_mnode));
    if (mem && sz)
      memcpy(node->mem, mem, sz);
    if (hdl)
      node->srchdl = hdl;
    node->callback = cb;
  }
  else
    cc_log_e("OOM\r\n");

  return node;
}

int cc_mnode_put(struct cc_mnode* node)
{
  int ret;
  if (!node)
    return -CC_EINVAL;
  else if (!node->srchdl)
  {
    cc_free(node);
    return CC_EOK;
  } 
  ret = cc_mempool_free(node->srchdl, node);
  return -ret;
}